package cn.gjxblog.transaction;

import cn.gjxblog.base.LogUtils;
import cn.gjxblog.base.ThreadUtils;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import org.apache.catalina.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Lazy;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.config.TaskManagementConfigUtils;
import org.springframework.stereotype.Service;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.DataSource;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 异步和事务同时存在测试
 * 测试不同线程之间事务是否存在关联，子线程抛出异常是否影响其他线程
 *
 * 结论：不同线程之间的事务完全隔离.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {AsyncAndTransactionTests.TransactionConfig.class, AsyncAndTransactionTests.AsyncConfig.class})
public class AsyncAndTransactionTests {

    @Autowired
    UserService userService;

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Test
    public void test(){
        LogUtils.printThreadInfo();
        jdbcTemplate.execute("insert into user (`name`,`age`) values ('Jack',22)");

        userService.saveUser();
        ThreadUtils.sleep(2);
    }

    @Service
    static class UserService{
        @Autowired
        ApplicationContext applicationContext;

        @Autowired
        JdbcTemplate jdbcTemplate;

        @Async
        @Transactional
        public void saveUser(){
            System.out.println(LogUtils.getThreadInfo()+"保存用户");
            jdbcTemplate.execute("insert into user (`name`,`age`) values ('JuLi',22)");
            applicationContext.getBean(UserService.class).sendMsg();
            ThreadUtils.sleep(1);
        }

        /**
         * 此线程抛出异常，事务回滚，但并不影响上面的两个调用链路，因为他们都处在不同的线程中
         */
        @Async
        @Transactional
        public void sendMsg(){
            System.out.println(LogUtils.getThreadInfo()+"投递消息");
            jdbcTemplate.execute("insert into user (`name`,`age`) values ('Mark',21)");
            int i = 10/0;
        }
    }




    @Configuration
    @EnableTransactionManagement
    static class TransactionConfig{
        @Bean
        public DataSource dataSource(){
            DataSource dataSource = new MysqlDataSource();
            ((MysqlDataSource) dataSource).setUser("root");
            ((MysqlDataSource) dataSource).setPassword("gjxblog");
            ((MysqlDataSource) dataSource).setServerName("mysql.db.gjxblog.cn");
            ((MysqlDataSource) dataSource).setPort(3306);
            ((MysqlDataSource) dataSource).setDatabaseName("test");
            return dataSource;
        }

        @Bean
        public PlatformTransactionManager transactionManager(){
            PlatformTransactionManager transactionManager = new DataSourceTransactionManager(dataSource());
            return transactionManager;
        }

        @Bean
        public UserService userService(){
            return new UserService();
        }

        @Bean
        public JdbcTemplate jdbcTemplate(){
            return new JdbcTemplate(dataSource());
        }

    }

    @Configuration
    @EnableAsync
    static class AsyncConfig implements AsyncConfigurer {
        @Override
        public Executor getAsyncExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(10); //核心线程数
            executor.setMaxPoolSize(20);  //最大线程数
            executor.setQueueCapacity(1000); //队列大小
            executor.setKeepAliveSeconds(300); //线程最大空闲时间
            executor.setThreadNamePrefix("fsx-Executor-"); ////指定用于新创建的线程名称的前缀。
            executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略（一共四种，此处省略）
            executor.initialize();
            return executor;
        }
    }




}
